--[=[
 规则

]=]


local table_insert = table.insert
local table_remove = table.remove
local math_random = math.random

local M = class("Rule")

function M:ctor()
    self.cards = new("games.texas.rule.cards")
    self.card_type = new("games.texas.rule.ptype")
    self.card_logic = new("games.texas.rule.cardlogic")
    self.algorithm = new("games.texas.rule.algorithm")

    self.common_cards = {}
    self.uids_cards = {}
    self.is_set_card = false --要过滤的牌

    --好牌库
    self.good_cards = {
        [10] = {
            { 0x0A, 0x0B, 0x0C, 0x0D, 0x0E },
        },
        [9] = {
            {0x17, 0x18, 0x19, 0x1A, 0x1B},
        },
        --4条
        [8] = {
            {0x02, 0x12, 0x22, 0x32, 0x03},
        },
        --葫芦
        [7] = {
            {0x02, 0x12, 0x22, 0x33, 0x03},
        },
        --同花
        [6] = {
            {0x02, 0x08, 0x03, 0x09, 0x0a},
        },
        --顺子
        [5] = {
            {0x02, 0x03, 0x06, 0x15, 0x14,},
            {0x12, 0x23, 0x2E, 0x15, 0x24,},
            {0x27, 0x38, 0x2b, 0x09, 0x1a,},
        },
        --3条
        [4] = {
            {0x02, 0x12, 0x22, 0x1a, 0x38,},
        },
    }

end

--计算牌值
function M:evaluate(user_cards, common_cards)
    local rank = 9999
    if not user_cards or not common_cards then
        --无牌
        return rank --最小牌型
    end
    if not next(user_cards) or #user_cards ~= 2 then
        --无手牌
        return rank
    end
    if not next(common_cards) then
        --无公牌
        local card1 = user_cards[1] & 0x0F
        local card2 = user_cards[2] & 0x0F
        if card1 == card2 then
            --对子
            rank = 6185 - card1
        end
        return rank
    end
    local svr_name = ".games.texas_rule.service".. math_random(1, 2)
    local res = g.call(svr_name, "evaluate", user_cards, common_cards)
    if not res then
        return rank
    end
    return res
end

--取牌型
function M:getKind(rank)
    return self.card_type:getKind(rank)
end

function M:getType(rank)
    return self.card_type:getType(rank)
end

--根据牌型取最好牌
function M:getBestCards(kind, hand_cards, common_cards)
    local cards = table.extend(hand_cards, common_cards)
    local ret = self.card_logic:findCardType(kind, cards)
    local best_cards = {}
    if ret then
        for _, v in ipairs(ret) do
            table_insert(best_cards, v)
        end
    end
    return best_cards
end

--洗牌
function M:shuffle()
    --self.common_cards = {
    --    0x02, 0x03, 0x04, 0x05, 0x06,
    --}

    --self:setRobotGoodCards()

    local ignore_cards = {}
    table.extend(ignore_cards, self.common_cards)
    for k, v in pairs(self.uids_cards) do
        table.extend(ignore_cards, v)
    end
    self.is_set_card = false
    if next(ignore_cards) then
        self.is_set_card = true
    end
    --
    self.cards:shuffleForRand(ignore_cards)

end

--取牌
function M:getNextCards(count, uid)
    if self.is_set_card and uid and next(self.uids_cards) and self.uids_cards[uid] then
        if next(self.uids_cards[uid]) then
            local cards = self.uids_cards[uid]
            self.uids_cards[uid] = nil
            return cards
        end
    end
    return self.cards:getNextCards(count)
end

--取公牌
function M:getCommonCards(count)
    if self.is_set_card and self.common_cards and next(self.common_cards) then
        local cards = {}
        local n = #self.common_cards
        g.log:warn("getCommonCards:", count, n, self.common_cards)
        for i = 1, n do
            local card = table_remove(self.common_cards)
            cards[i] = card
        end
        if n < count then
            local cs = self.cards:getNextCards(count - n)
            table.extend(cards, cs)
        end
        return cards
    end
    return self.cards:getNextCards(count)
end

--给指定玩家好牌
function M:setGoodCards(uid)
    --桌上所有玩家的手牌， 共公牌
    --计算出玩家的好牌
    --从牌中随机取出好牌作为公牌

    local has_player = false
    local user_cards = {}
    local users = g.desk:getPlayers()
    if not uid then
        --指定第一个机器人有好牌
        local robots = {}
        for _, user in pairs(users) do
            if user:isRobot() and user:isGaming() then
                table_insert(robots, user)
            end
        end
        local user = robots[math_random(1, #robots)]
        uid = user:getUid()
        table_insert(user_cards, user:getCards())

    else
        --指定玩家好牌
        for _, user in pairs(users) do
            if uid == user:getUid() and user:isGaming() then
                table_insert(user_cards, user:getCards())
                break
            end
        end
    end
    --牌桌是否有真人玩家在玩
    for _, user in pairs(users) do
        if uid ~= user:getUid() and user:isGaming() then
            table_insert(user_cards, user:getCards())
            if user:isPlayer() then
                has_player = true
            end
        end
    end
    --如果没真人，没机器人返回空
    if not uid then
        g.log:debug("uid is nil", g.tid)
        return
    end
    if not has_player then
        g.log:debug("has_player is nil", g.tid)
        return
    end
    if #user_cards < 2 then
        --最小要2个人有牌
        g.log:debug("#user_cards < 2", g.tid)
        return
    end
    local common_cards = g.desk.common_cards
    local outs = self.algorithm:getOutsForHoldCards(user_cards, common_cards)
    local cards = outs[1]
    --打乱顺序
    for i = #cards, 2, -1 do
        local j = math.random(i)
        cards[i], cards[j] = cards[j], cards[i]
    end
    --g.log:err("outs:", outs)
    --根据情况返回指定牌数
    local state = g.desk:getStage()
    if state == "flop" then
        --弱杀，先让前3张
        local kill_slow = true
        if kill_slow then
            return self.cards:getNextCards(3)
        else
            --强杀
            --返回3张
            if #cards >= 5 then
                local res = {cards[1], cards[2], cards[3]}
                --把已使用的card 从cards里删除
                for _, v in pairs(res) do
                    self.cards:removeCard(v)
                end
                return res
            else
                --可控牌太少，算是必杀失败了，让操作弃牌
                local user = g.user_mgr:getUser(uid)
                user:setCheatFail(true)
                return self.cards:getNextCards(3)
            end
        end

    elseif state == "turn" then
        if #cards > 0 then
            local res = {cards[1]}
            for _, v in pairs(res) do
                self.cards:removeCard(v)
            end
            return res
        end
    elseif state == "river" then
        if #cards > 0 then
            local res = {cards[1]}
            for _, v in pairs(res) do
                self.cards:removeCard(v)
            end
            return res
        end
    end

    local user = g.user_mgr:getUser(uid)
    user:setCheatFail(true) --杀牌失败了
    g.log:deskWarn(uid, "setGoodCards fail:")
    return self.cards:getNextCards(1)


end

--给指定玩家设置牌型, 下局生效
function M:setUserCardType(uid, card_type)
    --
    local cmd_cards = {
        ["10"] = function()
            self.common_cards = {0x0A, 0x0B, 0x0C}
            self.uids_cards[uid] = {0x0D, 0x0E}
        end,
        ["9"] = function()
            self.common_cards = {0x17, 0x18, 0x19}
            self.uids_cards[uid] = {0x1A, 0x1B}
        end,
        ["8"] = function()
            self.common_cards = {0x02, 0x12, 0x22}
            self.uids_cards[uid] = {0x32, 0x03}
        end,
    }
    if cmd_cards[card_type] then
        cmd_cards[card_type]()
    end
    print("setUserCardType:", uid, card_type)
end

--设置公牌的牌型
function M:setCommonCardType(card_type)
    --
    local cmd_cards = {
        ["10"] = function()
            self.common_cards = {0x0A, 0x0B, 0x0C, 0x0D, 0x0E}
        end,
        ["9"] = function()
            self.common_cards = {0x12, 0x13, 0x14, 0x15, 0x16}
        end,
        ["8"] = function()
            self.common_cards = {0x02, 0x12, 0x22, 0x32, 0x03}
        end,
        ["7"] = function()
            self.common_cards = {0x02, 0x12, 0x22, 0x13, 0x03}
        end,
    }
    if cmd_cards[card_type] then
        cmd_cards[card_type]()
    end
    print("setCommonCardType:", card_type)
end

--用于测试的命令
function M:testCmd(tb_cmd)
    if not g.const.switch.test_cmd then
        return
    end
    if g.desk:isMatchRoom() then
        if not g.const.switch.test_match_cmd then
            return
        end
    end
    local cmd = tb_cmd[1]
    local info = tb_cmd[2]
    if cmd == "tj" then --test_jackpot
        self:setUserCardType(uid, info)
    elseif cmd == "tc" then --设置公牌的牌型
        self:setCommonCardType(info)
    end
end

return M

